package com.ykt.model;

import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.TableMapping;
import com.ykt.common.utils.Colls;
import com.ykt.common.utils.SqlUtil;
import com.ykt.common.utils.Triple;
import com.ykt.common.utils.UB;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author long.hua
 * @version 1.0.0
 * @since 2016-01-20 23:14
 */
public class BaseModel<T extends Model<T>> extends Model<T> {
    private static final long serialVersionUID = 1L;

    private final static Logger LOGGER = LoggerFactory.getLogger(BaseModel.class);

    // 公共属性
    public static final String id = "id";
    public static final String name = "name";
    public final static String created_time = "created_time";
    public final static String updated_time = "updated_time";

    // 条件符号
    public static final String EQ = "EQ"; // 等于
    public static final String NE = "NE"; // 不等于
    public static final String GE = "GE"; // 大于等于
    public static final String LE = "LE"; // 小于等于
    public static final String LIKE = "LIKE"; // 右like
    public static final String OB = "OB"; // 排序 order by

    public static final String IN = "IN"; // in (...)


    public int getId() {
        return UB.i(getInt(id), -1);
    }

    public String getName() {
        return getStr(name);
    }

    public Date getCreatedTime() {
        return getDate(created_time);
    }

    public Date getUpdatedTime() {
        return getDate(updated_time);
    }

    /**
     * 将model转换成map, 只读
     *
     * @return
     */
    public Map<String, Object> getAttrMaps() {
        return super.getAttrs();
    }

    /**
     * 找到 model 中的单个属性, 并转化为 list
     *
     * @param sql    查询sql
     * @param attr   查找的属性名称，通常为表字段名
     * @param values 查询sql需的值
     * @return 指定属性名称值列表
     */
    public List<String> findByField(String sql, String attr, Object... values) {
        List<String> list = new ArrayList<>();

        List<Record> record = Db.find(sql, values);
        for (Record t : record) {
            list.add(t.getStr(attr));
        }

        return list;
    }

    protected String getTableName() {
        return TableMapping.me().getTable(getClass()).getName();
    }

    /**
     * 分页查询当前表数据，适合简单查询，一般供CMS使用
     *
     * @param pageNo   页号
     * @param pageSize 每页行数
     * @return
     */
    public Page<T> paginate(int pageNo, int pageSize) {
        return this.paginate(pageNo, pageSize, null);
    }

    /**
     * 分页查询当前表数据，适合简单查询，一般供CMS使用
     *
     * @param pageNo      页号
     * @param pageSize    每页行数
     * @param criteriaMap 查询条件与值、比较运算符
     * @return
     */
    public Page<T> paginate(int pageNo, int pageSize, Map<String, String> criteriaMap) {
        String select = "SELECT *";
        String from = " FROM " + getTableName();
        return this.paginate(select, from, pageNo, pageSize, criteriaMap);
    }

    /**
     * 分页查询当前表数据，适合简单查询，一般供CMS使用
     *
     * @param pageNo      页号
     * @param pageSize    每页行数
     * @param criteriaMap 查询条件与值、比较运算符
     * @return
     */
    protected Page<T> paginate(String select, String exceptSelect, int pageNo, int pageSize, Map<String, String> criteriaMap) {
        Section section = this.toSection(criteriaMap);
        if (section != null) {
            exceptSelect += " " + section.getWhere();
            exceptSelect += " " + section.getOrderBy();
        }

        if (section == null || Colls.isEmpty(section.getValues())) {
            return super.paginate(pageNo, pageSize, select, exceptSelect);
        }

        return super.paginate(pageNo, pageSize, select, exceptSelect, section.getValues().toArray());
    }

    protected Section toSection(Map<String, String> criteriaMap) {
        Section section = new Section();

        List<Object> values = new ArrayList<>();
        StringBuilder where = new StringBuilder("WHERE 1=1");
        for (Map.Entry<String, String> e : criteriaMap.entrySet()) {
            String value = e.getValue();
            if (StrKit.isBlank(value)) {
                continue;
            }

            String key = e.getKey();
            int index = key.indexOf("_");
            if (index > 0) {
                String flag = key.substring(0, index);
                String field = key.substring(index + 1);

                if (flag.equals(LIKE)) {
                    where.append(" AND ").append(field).append(" LIKE ?");
                    values.add(value.concat("%")); // 右Like，才可利用索引
                } else if (flag.equals(GE)) {
                    where.append(" AND ").append(field).append(" >= ?");
                    values.add(value);
                } else if (flag.equals(LE)) {
                    where.append(" AND ").append(field).append(" <= ?");
                    values.add(value);
                } else if (flag.equals(EQ)) {
                    where.append(" AND ").append(field).append(" = ?");
                    values.add(value);
                } else if (flag.equals(NE)) {
                    where.append(" AND ").append(field).append(" != ?");
                    values.add(value);
                } else if (flag.equals(IN)) { // 组装in条件
                    String items[] = value.split(",");
                    if (items.length > 0) {
                        String holder = SqlUtil.placeholder(items);
                        where.append(" AND ").append(field).append(" in ").append("(").append(holder).append(")");
                    }
                }
            }
        }
        section.setValues(values);
        section.setWhere(where.toString());

        String orderBy = criteriaMap.get(OB);
        if (orderBy == null || orderBy.isEmpty()) {
            section.setOrderBy("");
        } else {
            section.setOrderBy(orderBy);
        }

        return section;
    }

    /**
     * Sql片段
     */
    class Section {

        private String where;
        private String orderBy = ""; // 排序语句
        private List<Object> values; // sql语句中问号的对应的值

        public String getWhere() {
            return where;
        }

        public void setWhere(String where) {
            this.where = where;
        }

        public List<Object> getValues() {
            return values;
        }

        public void setValues(List<Object> values) {
            this.values = values;
        }

        public String getOrderBy() {
            return orderBy;
        }

        public void setOrderBy(String orderBy) {
            this.orderBy = orderBy;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("Section{");
            sb.append("where='").append(where).append('\'');
            sb.append(", orderBy='").append(orderBy).append('\'');
            sb.append(", values=").append(values);
            sb.append('}');
            return sb.toString();
        }
    }


    public String getCondition(Map<String, Object> conditionMap, Triple<String, String, String> fields[]) {
        if (conditionMap == null || conditionMap.isEmpty()) {
            return "";
        }

        String cond = "";

        for (Triple<String, String, String> item : fields) {
            String param = item.getF();
            String oper = item.getS();
            String field = item.getT();
            Object v = conditionMap.get(param);
            if (v == null) {
                continue;
            }

            if (v instanceof String || v instanceof Character) {
                cond += " AND " + field + oper + "\"" + v + "\"";
            } else if (v instanceof Byte || v instanceof Short || v instanceof Integer
                    || v instanceof Long || v instanceof Float || v instanceof Double) {
                cond += " AND " + field + oper + v;
            } else if (v instanceof Date) {
                cond += " AND " + field + oper + v;
            } else {
                cond += " AND " + field + oper + v;
            }
        }

        return cond;
    }


    public static void main(String[] args) {
        BaseModel bm = new BaseModel();
        Map<String, String> criteria = new HashMap<>();
        criteria.put(BaseModel.IN + "_id", "2,3,4");
        System.out.println(bm.toSection(criteria));
    }
}
